package com.xli.ui.module.framemoduleuser.service.impl;

import cn.hutool.core.util.IdUtil;
import com.alicp.jetcache.Cache;
import com.alicp.jetcache.CacheManager;
import com.alicp.jetcache.anno.CacheConsts;
import com.alicp.jetcache.anno.CacheType;
import com.alicp.jetcache.template.QuickConfig;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xli.ui.module.framemoduleuser.entity.FrameModuleUser;
import com.xli.ui.module.framemoduleuser.entity.ModuleUserCache;
import com.xli.ui.module.framemoduleuser.mapper.FrameModuleUserMapper;
import com.xli.ui.module.framemoduleuser.mapper.IModuleUserCacheMapper;
import com.xli.ui.module.framemoduleuser.service.IFrameModuleUserService;
import jakarta.annotation.PostConstruct;
import jakarta.validation.constraints.NotNull;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;

@Slf4j
@Validated
@Service
public class FrameModuleUserServiceImpl extends ServiceImpl<FrameModuleUserMapper, FrameModuleUser> implements IFrameModuleUserService {

    private final Lock lock = new ReentrantLock();

    @Autowired
    CacheManager cacheManager;

    Cache<Long, List<ModuleUserCache>> moduleUserCache;

    @PostConstruct
    public void init() {
        lock.lock();
        try {
            QuickConfig qc = QuickConfig.newBuilder("frame_module_user:list:")
                    .expire(Duration.ofSeconds(CacheConsts.DEFAULT_EXPIRE))
                    .cacheType(CacheType.BOTH)
                    .syncLocal(true)
                    .build();
            moduleUserCache = cacheManager.getOrCreateCache(qc);

            List<FrameModuleUser> frameModuleUserList = this.findList(new QueryWrapper<>());
            List<ModuleUserCache> cacheList = IModuleUserCacheMapper.INSTANCE.toCacheList(frameModuleUserList);

            // 根据用户分组
            Map<Long, List<ModuleUserCache>> groupUserList = cacheList.stream()
                    .collect(Collectors.groupingBy(ModuleUserCache::getUser_id));
            groupUserList.forEach((userId, moduleUserCacheList) -> {
                moduleUserCache.put(userId, moduleUserCacheList);
            });
            // 根据模块分组
            Map<Long, List<ModuleUserCache>> groupModuleList = cacheList.stream()
                    .collect(Collectors.groupingBy(ModuleUserCache::getModule_id));
            groupModuleList.forEach((moduleId, moduleUserCacheList) -> {
                moduleUserCache.put(moduleId, moduleUserCacheList);
            });
        } finally {
            lock.unlock();
        }
    }

    @Override
    public boolean insert(FrameModuleUser frameModuleUser) {
        lock.lock();
        try {
            boolean result = this.save(frameModuleUser);
            if (result) {
                List<ModuleUserCache> cacheList = moduleUserCache.get(frameModuleUser.getUser_id());
                if (cacheList == null) {
                    cacheList = new ArrayList<>();
                }
                cacheList.add(IModuleUserCacheMapper.INSTANCE.toCacheEntity(frameModuleUser));
                moduleUserCache.put(frameModuleUser.getUser_id(), cacheList);

                //更新模块分组
                cacheList = moduleUserCache.get(frameModuleUser.getModule_id());
                if (cacheList == null) {
                    cacheList = new ArrayList<>();
                }
                cacheList.add(IModuleUserCacheMapper.INSTANCE.toCacheEntity(frameModuleUser));
                moduleUserCache.put(frameModuleUser.getModule_id(), cacheList);
            }
            return result;
        } finally {
            lock.unlock();
        }
    }

    @Override
    public boolean insert(Long moduleId, List<String> userIds){
        for (String userId : userIds) {
            FrameModuleUser frameModuleUser = FrameModuleUser.builder()
                    .id(IdUtil.getSnowflakeNextId())
                    .module_id(moduleId)
                    .user_id(Long.valueOf(userId))
                    .build();
            insert(frameModuleUser);
        }
        return true;
    }

    @Override
    public boolean delete(Long id) {
        lock.lock();
        try {
            FrameModuleUser frameModuleUser = this.find(id);
            if (frameModuleUser != null) {
                boolean result = this.removeById(id);
                if (result) {
                    List<ModuleUserCache> cacheList = moduleUserCache.get(frameModuleUser.getUser_id());
                    if (cacheList == null) {
                        cacheList = new ArrayList<>();
                    }
                    cacheList.removeIf(moduleUserCache -> moduleUserCache.getId().equals(id));
                    moduleUserCache.put(frameModuleUser.getUser_id(), cacheList);

                    //更新模块分组
                    cacheList = moduleUserCache.get(frameModuleUser.getModule_id());
                    if (cacheList == null) {
                        cacheList = new ArrayList<>();
                    }
                    cacheList.removeIf(moduleUserCache -> moduleUserCache.getId().equals(id));
                    moduleUserCache.put(frameModuleUser.getModule_id(), cacheList);
                }
                return result;
            }
            return false;
        } finally {
            lock.unlock();
        }
    }

    @Override
    public boolean delete(Long moduleId, List<String> userIds) {
        for (String userId : userIds) {
            FrameModuleUser frameModuleUser = find(moduleId, Long.valueOf(userId));
            if (frameModuleUser != null) {
                this.delete(frameModuleUser.getId());
            }
        }
        return true;
    }

    @Override
    public boolean deleteByUserId(Long id) {
        lock.lock();
        try {
            QueryWrapper<FrameModuleUser> qw = new QueryWrapper<>();
            qw.lambda().eq(FrameModuleUser::getUser_id, id);
            List<FrameModuleUser> frameModuleUserList = this.findList(qw);
            for (FrameModuleUser frameModuleUser : frameModuleUserList) {
                this.delete(frameModuleUser.getId());
            }
            return true;
        } finally {
            lock.unlock();
        }
    }

    @Override
    public FrameModuleUser find(Long id) {
        return this.getById(id);
    }

    @Override
    public FrameModuleUser find(Long moduleId, Long userId){
        List<FrameModuleUser> frameModuleUserList= findModuleUserListByModuleId(moduleId);
        for (FrameModuleUser frameModuleUser : frameModuleUserList) {
            if (frameModuleUser.getUser_id().equals(userId)) {
                return frameModuleUser;
            }
        }
        return null;
    }

    @Override
    public long findCount(QueryWrapper<FrameModuleUser> qw) {
        return this.count(qw);
    }

    @Override
    public List<FrameModuleUser> findList(QueryWrapper<FrameModuleUser> qw) {
        return this.list(qw);
    }

    @Override
    public Page<FrameModuleUser> findList(QueryWrapper<FrameModuleUser> qw, long current, long size) {
        return this.page(new Page<>(current, size), qw);
    }

    @Override
    public List<FrameModuleUser> findModuleUserListByUserId(Long userId) {
        List<ModuleUserCache> cacheList = moduleUserCache.get(userId);
        if (cacheList == null) {
            cacheList = new ArrayList<>();
        }
        return IModuleUserCacheMapper.INSTANCE.toEntityList(cacheList);
    }

    @Override
    public List<FrameModuleUser> findModuleUserListByModuleId(Long moduleId) {
        List<ModuleUserCache> cacheList = moduleUserCache.get(moduleId);
        if (cacheList == null) {
            cacheList = new ArrayList<>();
        }
        return IModuleUserCacheMapper.INSTANCE.toEntityList(cacheList);
    }
}
